#include "mypipe.h"
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
/*
 * 请重构此库
 * 重构为open close read write模式
 * 以此来进行权限分割，防止“被骗”
 * */

//管道结构体
struct mypipe_st
{
    int head;               //头
    int tail;               //尾
    char data[PIPESIZE];    //数据区
    int datasize;           //占用大小
    pthread_mutex_t mut;    //互斥锁
    pthread_cond_t cond;    //信号量
    int count_rd;           //读者数量
    int count_wr;           //写者数量
};
//初始化函数
mypipe_t * mypipe_init(void)
{
    //为结构体申请空间
    struct mypipe_st * me;
    me = malloc( sizeof(*me));
    if(me == NULL)
    {
        return NULL;
    }
    //为结构体成员初始化
    me->head = 0;
    me->tail = 0;
    me->datasize = 0;
    me->count_rd = 0;
    me->count_wr = 0;
    pthread_mutex_init(&me->mut, NULL);
    pthread_cond_init(&me->cond, NULL);
    //返回结构地址
    return me;
}
//注册函数
int mypipe_register(mypipe_t * ptr, int opmap)
{
    struct mypipe_st * me = ptr;

    pthread_mutex_lock(&me->mut);                   //上锁
    if(opmap & (MYPIPE_READ | MYPIPE_WRITE) == 0)   //如果位图既不是读也不是写
    {
        return -1;
    }
    if(opmap & MYPIPE_READ)                         //如果读者
    {
        me->count_rd ++;
    }
    if(opmap & MYPIPE_WRITE)                        //如果写者
    {
        me->count_wr ++;
    }
    while(me->count_rd <= 0 || me->count_wr <= 0)   //当无人写或者无人读时则等待
    {
        pthread_cond_wait(&me->cond, &me->mut);
    }
    pthread_cond_broadcast(&me->cond);              //叫醒其他所有人
    pthread_mutex_unlock(&me->mut);                 //解锁

    return 0;
}
//注销函数
int mypipe_unregister(mypipe_t * ptr, int opmap)
{
    struct mypipe_st * me = ptr;
    pthread_mutex_lock(&me->mut);                   //上锁
    if(opmap & MYPIPE_READ)
    {
        me->count_rd --;
    }
    if(opmap | MYPIPE_WRITE)
    {
        me->count_wr --;
    }
    pthread_cond_broadcast(&me->cond);
    pthread_mutex_unlock(&me->mut);
    return 0;
}
//读字节小函数
static int mypipe_readbyte_unlock(struct mypipe_st * me, char * datap)
{
    if(me->datasize <= 0)
    {
        return -1;
    }
    *datap = me->data[me->head];

    me->head = next(me->head);
    me->datasize --;

    return 0;
}
//读数据函数
int mypipe_read(mypipe_t * ptr, void * buf, size_t count)
{
    struct mypipe_st * me = ptr;
    int i;

    pthread_mutex_lock(&me->mut);                       //上锁
    while(me->datasize <= 0 && me->count_wr > 0)        //若管道无数据且有人写则等待
    {
        pthread_cond_wait(&me->cond, &me->mut);
    }
    if(me->datasize <= 0 && me->count_wr <= 0)          //若管道无数据且无人写则不等了
    {
        pthread_cond_broadcast(&me->cond);              //叫醒其他所有人
        pthread_mutex_unlock(&me->mut);                 //解锁
        return 0;
    }
    for(i = 0; i < count; i++)                          //最多进行count次读单一字节
    {
        if(mypipe_readbyte_unlock(me, buf + i) != 0)    //如果返回值不为〇(即管道内无数据)就跳出
        {
            break;
        }
    }
    pthread_cond_broadcast(&me->cond);                  //叫醒其他所有人
    pthread_mutex_unlock(&me->mut);                     //解锁

    //返回实际读到的字节数
    return i;
}
//写字节小函数
static int mypipe_writebyte_unlock(struct mypipe_st * me, char * datap)
{
    if(me->datasize == PIPESIZE)
    {
        return -1;
    }
    me->data[me->tail] = *datap;

    me->tail = next(me->tail);
    me->datasize ++;

    return 0;
}
//写数据函数
int mypipe_write(mypipe_t * ptr, const void * buf, size_t count)
{
    struct mypipe_st * me = ptr;
    int i;

    pthread_mutex_lock(&me->mut);                       //上锁
    while(me->datasize == PIPESIZE && me->count_rd > 0) //若管道满且有人读则等待
    {
        pthread_cond_wait(&me->cond, &me->mut);
    }
    if(me->datasize == PIPESIZE && me->count_rd <= 0)   //若管道满且无人读则不等了
    {
        pthread_cond_broadcast(&me->cond);              //叫醒其他所有人
        pthread_mutex_unlock(&me->mut);                 //解锁
        return 0;
    }
    for(i = 0; i < count; i++)                          //最多进行count次读单一字节
    {
        if(mypipe_writebyte_unlock(me, buf + i) != 0)   //如果返回值不为〇(即管道满了)就跳出
        {
            break;
        }
    }
    pthread_cond_broadcast(&me->cond);                  //叫醒其他所有人
    pthread_mutex_unlock(&me->mut);                     //解锁

    //返回实际写入的字节数
    return i;
}
//销毁管道函数
int mypipe_destroy(mypipe_t *ptr)
{
    struct mypipe_st * me = ptr;

    pthread_mutex_destroy(&me->mut);
    pthread_cond_destroy(&me->cond);

    free(me);

    return 0;
}